package com.atguigu.gulimall.auth.web;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import com.atguigu.common.constant.AuthServerConstant;
import com.atguigu.common.exception.BizCodeEnum;
import com.atguigu.common.utils.R;
import com.atguigu.common.vo.MemberResponseVo;
import com.atguigu.gulimall.auth.feign.MemberFeignService;
import com.atguigu.gulimall.auth.feign.ThirdPartyFeignService;
import com.atguigu.gulimall.auth.vo.UserLoginVo;
import com.atguigu.gulimall.auth.vo.UserRegistVo;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @create: 2024/9/5
 * @author: gyhe10
 * @description:
 **/

@Controller
public class LoginController {

    // 在自定义的 Spring MVC 配置类中，重写 addViewControllers 方法，添加自定义的视图控制器，实现了登录页面和注册页面的自动跳转。
    // @GetMapping("/login.html")
    // public String loginPage() {
    //     return "login";
    // }
    //
    // @GetMapping("/reg.html")
    // public String regPage() {
    //     return "reg";
    // }

    @Resource
    private ThirdPartyFeignService thirdPartyFeignService;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private MemberFeignService memberFeignService;

    /**
     * 调用 third-party 服务，发送短信验证码
     * @return
     */
    @ResponseBody
    @GetMapping("/sms/sendCode")
    public R sendCode(@RequestParam("phone") String phone) {
        // 短信验证码接口防刷
        String redisCode = stringRedisTemplate.opsForValue().get(AuthServerConstant.SMS_CODE_CACHE_PREFIX + phone);
        if (StringUtils.hasText(redisCode)) {
            long l = Long.parseLong(redisCode.split("_")[1]);
            if (System.currentTimeMillis() - l < 60000) {
                return R.error(BizCodeEnum.SMS_CODE_EXCEPTION.getCode(), BizCodeEnum.SMS_CODE_EXCEPTION.getMsg());
            }
        }
        if (StringUtils.hasText(phone)) {
            String code = String.valueOf(RandomUtil.randomInt(1000, 9999));
            String str = code + "_" + System.currentTimeMillis();
            // 缓存验证码方便后续校验 key = sms:code:phone value = code
            stringRedisTemplate.opsForValue().set(AuthServerConstant.SMS_CODE_CACHE_PREFIX + phone, str, 10, TimeUnit.MINUTES);
            thirdPartyFeignService.sendCode(phone, code);
            return R.ok();
        }
        return R.error(BizCodeEnum.PHONE_NUMBER_INVALID.getCode(), BizCodeEnum.PHONE_NUMBER_INVALID.getMsg());
    }

    /**
     * 用户注册
     * @param vo 用户在注册页提交的数据
     * @param result 校验注解的校验结果
     * @param redirectAttributes RedirectAttributes 是 Spring MVC 提供的一个接口，用于在重定向过程中传递数据。它允许你在控制器方法中设置需要传递的数据，然后在重定向目标页面中获取这些数据。
     * @return
     */
    @PostMapping("/regist")
    public String regist(@Validated UserRegistVo vo, BindingResult result, RedirectAttributes redirectAttributes) {
        if (result.hasErrors()) {
            // 获取错误信息，转为 Map
            Map<String, String> errors = result.getFieldErrors().stream().collect(Collectors.toMap(FieldError::getField, DefaultMessageSourceResolvable::getDefaultMessage));
            // 将错误信息添加到 RedirectAttributes，用于页面显示
            // 错误信息在重定向后，会被取出来，显示在页面上，仅在下一次请求中有效
            redirectAttributes.addFlashAttribute("errors", errors);

            // 验证失败，返回注册页
            return "redirect:http://auth.gulimall.com/reg.html";
        }

        // 校验验证码
        // 通过参数校验的验证码，肯定不为 null
        String code = vo.getCode();
        String redisCode = stringRedisTemplate.opsForValue().get(AuthServerConstant.SMS_CODE_CACHE_PREFIX + vo.getPhone());
        if (!StringUtils.hasText(redisCode) || !redisCode.split("_")[0].equals(code)) {
            // 验证码错误，返回注册页
            Map<String, String> errors = new HashMap<>();
            errors.put("code", "验证码错误");
            redirectAttributes.addFlashAttribute("errors", errors);
            return "redirect:http://auth.gulimall.com/reg.html";
        }

        // 验证码校验通过，删除 Redis 中的验证码
        stringRedisTemplate.delete(AuthServerConstant.SMS_CODE_CACHE_PREFIX + vo.getPhone());

        // 远程调用 member 服务进行注册
        R r = memberFeignService.regist(vo);
        if (r.getCode() == 0) {
            // 注册成功，返回登录页
            return "redirect:http://auth.gulimall.com/login.html";
        } else {
            // 注册失败，封装错误提示信息，返回注册页
            Map<String, String> errors = new HashMap<>();
            errors.put("msg", r.get("msg").toString());
            redirectAttributes.addFlashAttribute("errors", errors);
            return "redirect:http://auth.gulimall.com/reg.html";
        }
    }

    @PostMapping("/login")
    public String login(UserLoginVo vo, RedirectAttributes redirectAttributes, HttpSession session) {
        // 远程调用 member 服务进行登录
        R r = memberFeignService.login(vo);
        if (r.getCode() == 0) {
            // 登录成功，跳转到首页
            Object object = r.get("data");
            MemberResponseVo memberResponseVo = JSONUtil.toBean(JSONUtil.toJsonStr(object), MemberResponseVo.class);
            session.setAttribute(AuthServerConstant.LOGIN_USER, memberResponseVo);
            return "redirect:http://gulimall.com";
        } else {
            // 登录失败，封装错误提示信息，返回登录页
            Map<String, String> errors = new HashMap<>();
            errors.put("msg", r.get("msg").toString());
            redirectAttributes.addFlashAttribute("errors", errors);
            return "redirect:http://auth.gulimall.com/login.html";
        }
    }

    /**
     * 判断 HttpSession 是否存在用户信息，如果没有就跳转登录页，如果有跳转到首页
     * @param session
     * @return
     */
    @GetMapping("/login.html")
    public String loginPage(HttpSession session) {
        Object attribute = session.getAttribute(AuthServerConstant.LOGIN_USER);
        if (attribute == null) {
            // 没有登录，跳转到登录页
            return "login";
        } else {
            // 已经登录，跳转到首页
            return "redirect:http://gulimall.com";
        }
    }
}
